package cn.brian.framework.log;

import cn.brian.modular.log.entity.SysLog;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.core.task.TaskExecutor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

/**
 * 
 * @author
 * @create
 * 日志AOP,标准日志格式logback-spring.xml
 * 如果开启日志记录，需要多数据配置
 */
@Slf4j 
@Aspect
@Order(-1) // 保证该AOP在@Transactional之前执行
public class LogAnnotationAOP {

	@Around("@annotation(ds)")
	public Object logSave(ProceedingJoinPoint joinPoint, LogAnnotation ds) throws Throwable {

		String traceId="xxxxooooo";
		log.info(traceId);
		// 请求流水号
		// 记录开始时间
		long start = System.currentTimeMillis();
		// 获取方法参数
		String url = null;
		String httpMethod = null;
		Object result = null;
		List<Object> httpReqArgs = new ArrayList<Object>();
		List<Object> httpReqParameterTypes = new ArrayList<Object>();
		SysLog sysLog = new SysLog();
		sysLog.setCreateTime(new Date());
		sysLog.setUsername("测试用户");
		MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
		Method method=methodSignature.getMethod();
		StringBuffer methodsb=new StringBuffer();
		Class<?>[] cls=method.getParameterTypes();
		for(Class c1:cls){
			httpReqParameterTypes.add(c1.getName());
		}
		// 得到方法的返回值类型的类类型
		Class<?> returnType = method.getReturnType();
		methodsb.append(returnType.getName() + " ").append(methodSignature.getDeclaringTypeName()).append(".");
		// 得到方法的名称
		methodsb.append(method.getName() + "(");
		// 获取参数类型
		Class[] paramTypes = method.getParameterTypes();
		for (int i=0;i<paramTypes.length;i++) {
			Class class2=paramTypes[i];
			if(i>0){
				methodsb.append(",");
			}
			methodsb.append(class2.getName());
		}
		methodsb.append(")");
		Class[] exceptionTypes=method.getExceptionTypes();
		if(exceptionTypes.length>0){
			methodsb.append(" throws ");
			for (int i=0;i<exceptionTypes.length;i++) {
				Class class3=exceptionTypes[i];
				if(i>0){
					methodsb.append(",");
				}
				methodsb.append(class3.getName());
			}
		}

		LogAnnotation logAnnotation = methodSignature.getMethod().getDeclaredAnnotation(LogAnnotation.class);
		sysLog.setModule(logAnnotation.module() + ":" + methodSignature.getDeclaringTypeName() + "/"
				+ methodSignature.getName());
		// 参数值
		Object[] args = joinPoint.getArgs();
		url =  methodSignature.getDeclaringTypeName() + "/"+ methodSignature.getName();
		String params = null ;
		log.info("参数：{}",methodsb.toString());
		for (Object object : args) {
			if (object instanceof HttpServletRequest) {
				HttpServletRequest request = (HttpServletRequest) object;
				url = request.getRequestURI();
				httpMethod = request.getMethod();
			} else if (object instanceof HttpServletResponse) {
			} else {
				
				httpReqArgs.add(object);
			}
		}

		try {
			params=JSONArray.toJSONString(httpReqArgs);
			sysLog.setParams(params);
			// 打印请求参数参数
			log.info("开始请求，traceId={},  url={} , httpMethod={}, reqData={} ", traceId, url, httpMethod, params);
		} catch (Exception e) {
			log.error("记录参数失败：{}", e.getMessage());
		}

		try {
			// 调用原来的方法
			result = joinPoint.proceed();
			sysLog.setFlag(Boolean.TRUE);
		} catch (Exception e) {
			sysLog.setFlag(Boolean.FALSE);
			sysLog.setRemark(e.getMessage());
			log.error("请求报错，traceId={},  url={} , httpMethod={}, reqData={} ,error ={} ", traceId, url, httpMethod, params,e.getMessage());
			throw e;
		} finally {
			
////			log.info(SecurityContextHolder.getContext().getAuthentication().getPrincipal()+"");
//
//			//如果需要记录数据库开启异步操作
//			if (logAnnotation.recordRequestParam()) {
//				CompletableFuture.runAsync(() -> {
//					try {
//
////							log.info(SecurityContextHolder.getContext().getAuthentication().getPrincipal()+"");
//							log.trace("日志落库开始：{}", sysLog);
//							if(logService!=null){
//								logService.save(sysLog);
//							}
//							log.trace("开始落库结束：{}", sysLog);
//
//
//					} catch (Exception e) {
//						log.error("落库失败：{}", e.getMessage());
//					}
//
//				}, taskExecutor);
//			}
			 
			// 获取回执报文及耗时
			log.info("请求完成, traceId={}, 耗时={}, resp={}:", traceId, (System.currentTimeMillis() - start),
					result == null ? null : JSON.toJSONString(result));
			log.info("syslog:{}", JSON.toJSONString(sysLog));
			//syslog:{"createTime":1591343498494,"flag":true,"module":"log-center:cn.brian.modular.log.controller.LogController/queryList","params":"[\"9\"]","username":"测试用户"}
		}
		return result;
	}

	
	
	
	/**
	 * 生成日志随机数
	 * 
	 * @return
	 */
	public String getRandom() {
		int i = 0;
		StringBuilder st = new StringBuilder();
		while (i < 5) {
			i++;
			st.append(ThreadLocalRandom.current().nextInt(10));
		}
		return st.toString() + System.currentTimeMillis();
	}

}